#include "TransformHierarchy.hpp"

using namespace Typhoon;

TransformHierarchy::TransformHierarchy() {
	AddComponent<Hierarchy>();
	AddComponent<Transform>();
}

void TransformHierarchy::GameObjectAdded(GameObject* gameObject) {
	Transform* transform = gameObject->GetComponent<Transform>();
	//transform->World.HasBecomeDirty += event_handler(this, &TransformHierarchy::WorldHasBecomeDirty);
	transform->World.Method += event_handler(this, &TransformHierarchy::CalcWorld);
	Hierarchy* hierarchy = gameObject->GetComponent<Hierarchy>();
	hierarchy->Parent.ChangedWithOld += event_handler(this, &TransformHierarchy::ParentChanged);
	Property<Hierarchy*, GameObject*>::EventData e;
	e.owner = hierarchy;
	e.Old = 0;
	e.Current = hierarchy->Parent;
	ParentChanged(e);
}

void TransformHierarchy::GameObjectRemoved(GameObject* gameObject) {
	Transform* transform = gameObject->GetComponent<Transform>();
	//transform->World.HasBecomeDirty -= event_handler(this, &TransformHierarchy::WorldHasBecomeDirty);
	transform->World.Method -= event_handler(this, &TransformHierarchy::CalcWorld);
	gameObject->GetComponent<Hierarchy>()->Parent.ChangedWithOld -= event_handler(this, &TransformHierarchy::ParentChanged);
}
/*
void TransformHierarchy::LocalTransformChanged(Transform* transform) {
	
	Hierarchy* hierarchy = transform->gameObject->GetComponent<Hierarchy>();
	GameObject* parent = hierarchy->Parent;
	if (parent) {
		Matrix4x4* mat = transform->Local.GetValue();
		transform->World = mat->operator*(parent->GetComponent<Transform>()->World);
	} else {
		transform->Transform = localTransform->Transform;
	}
	
}


void TransformHierarchy::WorldTransformChanged(Transform* transform) {
	
	Hierarchy* hierarchy = transform->gameObject->GetComponent<Hierarchy>();
	int children = hierarchy->ChildrenCount();

	for(int i=0; i<children; i++) {
		GameObject* child = hierarchy->GetChild(i);
		Matrix3x3* mat = child->GetComponent<LocalTransform>()->Transform.GetValue();
		child->GetComponent<WorldTransform>()->Transform = mat->operator*(transform->Transform);
	}
	
}
*/

void TransformHierarchy::CalcWorld( DirtyProperty<Transform*, Matrix4x4>::EventData& event )
{
	Hierarchy* hierarchy = event.owner->gameObject->GetComponent<Hierarchy>();
	Matrix4x4& world = *event.Value;

	if (!hierarchy->Parent) {
		//world = event.Owner->Local; // implemented in Transform component
	} else {
		GameObject* parent = hierarchy->Parent;
		//world = event.Owner->Local.GetValue()->Multiply(*parent->GetComponent<Transform>()->World.GetValue());
		world = parent->GetComponent<Transform>()->World.GetValue()->Multiply(*event.owner->Local.GetValue());
	}
}

//void TransformHierarchy::ParentChanged( Hierarchy* hierarchy ) {
//	hierarchy->gameObject->GetComponent<Transform>()->World.MakeDirty();
//}

void TransformHierarchy::ParentChanged( Property<Hierarchy*, GameObject*>::EventData event ) {

	Transform* transform = event.owner->gameObject->GetComponent<Transform>();
	transform->World.MakeDirty();
	transform->WorldInverse.MakeDirty();

	if (event.Old) {
		transform->UnHookOther(event.Old->GetComponent<Transform>());
	}

	if (event.Current) {
		transform->HookOther(event.Current->GetComponent<Transform>());
	}
}
